
#include "elasys_server.h"
#include <elapi.h>
#include "CContainer.h"

INLINE _TObjectEnumerator::_TObjectEnumerator(
    ObjectNode *pHeader,
    CCriticalSection *pLock,
    Int32 *pState)
{
    m_pHeader = m_pCurrent = pHeader;
    m_pLock = pLock;
    m_pState = pState;
    m_nOrigState = *pState;
}


UInt32 _TObjectEnumerator::AddRef()
{
    return (UInt32)m_cRef.Increment();
}

UInt32 _TObjectEnumerator::Release()
{
    Int32 nRef = m_cRef.Decrement();

    if (0 == nRef) {
        delete this;
    }
    return nRef;
}

PInterface _TObjectEnumerator::Probe(
    REIID riid)
{
    if (EIID_IInterface == riid) {
        return (IInterface *)this;
    }
    else if (EIID_IObjectEnumerator == riid) {
        return (IObjectEnumerator *)this;
    }
    else if (EIID_INTERFACE_INFO == riid) {
        return (IInterface *)&EIID_IObjectEnumerator;
    }
    else {
        return NULL;
    }
}

ECode _TObjectEnumerator::Aggregate(
    AggregateType type, PInterface pObj)
{
    return E_NOT_IMPLEMENTED;
}

ECode _TObjectEnumerator::GetDomain(
    PInterface *ppObj)
{
    return E_NOT_IMPLEMENTED;
}

ECode _TObjectEnumerator::Current(
    /* [out] */ PInterface *ppObj)
{
    if (NULL == ppObj) return E_INVALID_ARGUMENT;
    if (NULL == m_pCurrent || m_pHeader == m_pCurrent) {
        return E_INVALID_OPERATION;
    }

    m_pLock->Enter();

    if (m_nOrigState != *m_pState) {
        m_pCurrent = NULL;
        m_pLock->Leave();
        return E_INVALID_OPERATION;
    }

    *ppObj = m_pCurrent->m_pObject;
    m_pCurrent->m_pObject->AddRef();
    m_pLock->Leave();
    return NOERROR;
}

ECode _TObjectEnumerator::MoveNext(Boolean *pSucceeded)
{
    if (NULL == m_pCurrent) {
        *pSucceeded = FALSE;
        return E_INVALID_OPERATION;
    }

    m_pLock->Enter();

    if (m_nOrigState != *m_pState) {
        m_pCurrent = NULL;
        m_pLock->Leave();
        *pSucceeded = FALSE;
        return E_INVALID_OPERATION;
    }

    if (m_pCurrent == m_pHeader->Prev()) {
        m_pCurrent = NULL;
        m_pLock->Leave();
        *pSucceeded = FALSE;
        return NOERROR;
    }

    m_pCurrent = (ObjectNode *)m_pCurrent->Next();
    m_pLock->Leave();
    *pSucceeded = TRUE;
    return NOERROR;
}

ECode _TObjectEnumerator::Reset()
{
    m_pCurrent = m_pHeader;
    m_nOrigState = *m_pState;
    return NOERROR;
}

ECode CContainer::Add(
    /* [in] */ IInterface *pObject)
{
    ObjectNode *pNode;

    m_lock.Enter();

    pNode = new ObjectNode(pObject);
    if (NULL == pNode) {
        m_lock.Leave();
        return E_OUT_OF_MEMORY;
    }

    SimpleContainer::Add(pNode);
    m_nCount++;
    m_nState++;

    m_lock.Leave();

    return NOERROR;
}

ECode CContainer::Remove(
    /* [in] */ IInterface *pObject)
{
    ObjectNode *pNode;

    m_lock.Enter();

    ForEachDLinkNode(ObjectNode *, pNode, &m_head) {
        if (pNode->m_pObject == pObject) {
            SimpleContainer::Remove(pNode);
            m_nCount--;
            m_nState++;
            delete pNode;
            m_lock.Leave();
            return NOERROR;
        }
    }

    m_lock.Leave();

    return S_FALSE;
}

ECode CContainer::GetCount(
    /* [out] */ Int32 *pCount)
{
    if (NULL == pCount) {
        return E_INVALID_ARGUMENT;
    }

    *pCount = m_nCount;

    return NOERROR;
}

ECode CContainer::GetEnumerator(
    /* [in] */ IObjectEnumerator **ppEnumerator)
{
    if (NULL == ppEnumerator) {
        return E_INVALID_ARGUMENT;
    }

    _TObjectEnumerator *pEnum;

    pEnum = new _TObjectEnumerator(
            (ObjectNode *)&m_head,
            &m_lock,
            &m_nState);
    if (NULL == pEnum) {
        return E_OUT_OF_MEMORY;
    }
    *ppEnumerator = (IObjectEnumerator *)pEnum;
    pEnum->AddRef();

    return NOERROR;
}

ECode CContainer::Dispose()
{
    ObjectNode *pNode;

    m_lock.Enter();

    m_nCount = 0;
    m_nState++;

    pNode = (ObjectNode *)m_head.Next();
    while (&m_head != (DLinkNode *)pNode) {
        pNode->Detach();
        delete pNode;
        pNode = (ObjectNode *)m_head.Next();
    }
    m_pCurrent = NULL;

    m_lock.Leave();

    return NOERROR;
}
